package com.xbongbong.paas.statistics.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.StatisticPaasFormDataEsEntity;
import com.xbongbong.paas.elasticsearch.constant.EsMappingConstant;
import com.xbongbong.paas.elasticsearch.model.PaasFormDataEsModel;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.BiRelTableEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.SubFieldTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.pojo.dto.DepartmentListDTO;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsInitVO;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsListVO;
import com.xbongbong.paas.statistics.entity.CorrelationEntity;
import com.xbongbong.paas.statistics.pojo.dto.SlaveListDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.ReflectHelper;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.pro.constant.XbbProConstant;
import com.xbongbong.pro.domain.entity.BiDataCorrelationEntity;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.enums.errorcodes.StatisticsServicesErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.statistic.enums.ChartTypeEnum;
import com.xbongbong.pro.statistic.help.CustomHelp;
import com.xbongbong.pro.statistic.model.BiDataCorrelationModel;
import com.xbongbong.pro.statistic.model.ChartModel;
import com.xbongbong.pro.statistic.pojo.SlaveSourcePojo;
import com.xbongbong.pro.statistic.result.pojo.dto.ChartResultDTO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultTableVO;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.dao.ContractDao;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.PaasFormDataModel;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * 创建时间： 2018/12/11 15:21
 * 修改时间： 2018/12/11 15:21 梁鲁江
 *
 * @author 梁鲁江
 */
@RestController
@RequestMapping(XbbProConstant.API_ROOT_PREFIX + "/chart/demo")
public class AggDemoController {

    @Resource
    private CustomerModel customerModel;
    @Resource
    private PaasFormDataEsModel paasFormDataEsModel;
    @Resource
    private PaasFormDataModel paasFormDataModel;
    @Resource
    private EsHelper esHelper;
    @Resource
    private ChartModel chartModel;
    @Resource
    private BiDataCorrelationModel biDataCorrelationModel;
    @Resource
    private CustomHelp customHelp;
    @Resource
    private ContractDao contractDao;

    String statisticIndexName = "index_statistic_pass_data";
    String statisticType = IndexTypeEnum.IDX_FORM_DATA.getType();
    @RequestMapping(value = "/test", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String test(@RequestBody @Valid DepartmentListDTO departmentListDTO, BindingResult br) throws Exception {
        XbbResponse<PaasFormDataEntityExt> response;
            String data = "{\"addTime\":1537429468,\"address\":\"\",\"approveStatus\":0,\"city\":\"\",\"corpid\":\"xbb5e5c25632148409fb888704b0af4cbd7\",\"country\":\"\",\"customerStageId\":0,\"customerTeam\":[{\"addTime\":1537429468,\"backTime\":0,\"corpid\":\"xbb5e5c25632148409fb888704b0af4cbd7\",\"customerId\":7038469,\"del\":0,\"distributionTime\":1537429468,\"id\":8772294,\"isMain\":1,\"position\":\"\",\"updateTime\":1537429468,\"userAvatar\":\"\",\"userId\":\"1494346679814\",\"userName\":\"卡卡西\"}],\"del\":0,\"district\":\"\",\"fax\":\"\",\"fieldEntity\":{\"addTime\":1537429468,\"attr1\":\"\",\"attr10\":\"\",\"attr11\":\"\",\"attr12\":\"\",\"attr13\":\"\",\"attr14\":\"\",\"attr15\":\"\",\"attr16\":\"\",\"attr17\":\"\",\"attr18\":\"\",\"attr19\":\"\",\"attr2\":\"\",\"attr20\":\"\",\"attr21\":\"\",\"attr22\":\"\",\"attr23\":\"\",\"attr24\":\"\",\"attr25\":\"\",\"attr26\":\"\",\"attr27\":\"\",\"attr28\":\"\",\"attr29\":\"\",\"attr3\":\"\",\"attr30\":\"\",\"attr31\":\"\",\"attr32\":\"\",\"attr33\":\"\",\"attr34\":\"\",\"attr35\":\"\",\"attr36\":\"\",\"attr37\":\"\",\"attr38\":\"\",\"attr39\":\"\",\"attr4\":\"\",\"attr40\":\"\",\"attr5\":\"\",\"attr6\":\"\",\"attr7\":\"\",\"attr8\":\"\",\"attr9\":\"\",\"corpid\":\"xbb5e5c25632148409fb888704b0af4cbd7\",\"empty\":true,\"id\":8189831,\"refId\":7038469,\"refType\":1,\"salesStageCode\":0,\"templateId\":5350,\"updateTime\":1537429468},\"healthDegree\":0,\"id\":7038469,\"importantDegree\":0,\"industry\":0,\"instruction\":\"\",\"isArchived\":0,\"isIndividual\":0,\"isLunarBirthdayShown\":0,\"isPublic\":0,\"lastConnectTime\":1537429469,\"lastConnectTimeStr\":\"\",\"latitude\":0,\"location\":{\"lat\":0,\"lon\":0},\"longitude\":0,\"mainContactName\":\"\",\"mainContactPhone\":\"[]\",\"mainContactPhoneShow\":\"\",\"name\":\"17682300964\",\"nameShort\":\"\",\"phoneJsonArray\":[{\"name\":\"工作\",\"telNum\":\"17682300964\"}],\"province\":\"\",\"scale\":0,\"source\":\"\",\"tagLinkList\":[],\"templateId\":5350,\"type\":1,\"updateTime\":1537429468,\"userId\":\"1494346679814\",\"userName\":\"\",\"website\":\"\",\"zipCode\":\"\"}";
            PaasFormDataEntityExt entity = new PaasFormDataEntityExt();
            entity.setAddTime(1537240575L);
            entity.setAppId(5000001L);
            entity.setCorpid("1");
            entity.setCreatorId("2");
            entity.setData(JSON.parseObject(data));
            entity.setDataId(5000001L);
            entity.setDepartmentId(1L);
            entity.setEsId("1_5000006");
            entity.setFlowStatus(0);
            entity.setFormId(5000001L);
            entity.setMenuId(5000001L);
            entity.setUpdateTime(1537240575L);
            entity.setSerialNo("SO.100002");
            entity.setOwnerId("1");
            response=  new XbbResponse<>(entity);
        return JSON.toJSONString(response);
    }

    @RequestMapping(value = "/test2",method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String test2(@RequestBody @Valid DepartmentListDTO departmentListDTO,BindingResult br){
        XbbResponse response;
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery(ParameterConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD,"1"));
        boolQueryBuilder.filter(termQuery("atformId",6375));
        boolQueryBuilder.filter(termQuery("btformId",6374));
        boolQueryBuilder.filter(termQuery("ctformId",6376));
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        return JSON.toJSONString("success");
    }

    /**
     * 自定义图表渲染接口测试
     * @param chartResultDTO
     * @param br
     * @return
     * @throws XbbException
     */
    @RequestMapping(value = "/test3",method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String test3(@RequestBody @Valid ChartResultDTO chartResultDTO, BindingResult br) throws XbbException{
    XbbResponse response;
    if (br.hasErrors()){
        String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
        response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002,errMsg);
    } else {
        //请求参数后处理，比如del、enable
        chartResultDTO.postProcess();
        //塞入map
        Map<String, Object> map = BeanUtil.convertBean2Map(chartResultDTO, true);
        List<ChartEntity> list = chartModel.findEntitys(map);
        if(list == null || list.size() == 0) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012, StatisticsServicesErrorCodeEnum.API_ERROR_224012.getMsg());
        }
        JSONArray array = new JSONArray();
        for (ChartEntity chartEntity : list) {
            JSONObject result = chartRender(chartEntity);
            array.add(result);

        }
        return JSON.toJSONString(array);
    }
        return null;
    }

    /**
     * 图表渲染
     * @param chartEntity
     * @return
     * @throws XbbException
     */
    private JSONObject chartRender(ChartEntity chartEntity) throws XbbException{
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery(ParameterConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD,chartEntity.getCorpid()));
/*        nativeSearchQueryBuilder.withQuery(boolQueryBuilder)
                .withIndices("idx_statistic_pass_data")
                .withTypes("statistic_pass_data");
        SearchQuery searchQuery = nativeSearchQueryBuilder.build();*/
        JSONObject driverSourcesObject = chartEntity.getDriverSources();
        SlaveSourcePojo driverSourcePojo = JSON.toJavaObject(driverSourcesObject, SlaveSourcePojo.class);
        JSONArray slaveSourcesObject = chartEntity.getSlaveSources();
        //数据表顺序
        List<SlaveSourcePojo> slaveSourceListForCorrelation = new ArrayList<>();
        String formId = "formId";
        //主数据表
        if(!driverSourcesObject.isEmpty()){
            if(driverSourcePojo.getFormId()!=null){
                boolQueryBuilder.filter(termQuery("atformId",driverSourcePojo.getFormId()));
            }
        }
        //从数据表
        if(!slaveSourcesObject.isEmpty()){
            JSONObject jsonObject = (JSONObject) slaveSourcesObject.get(0);
            boolean hasSecondSlave = false;
            if(slaveSourcesObject.size()>1){
                hasSecondSlave = true;
            }
            //把 主数表 先装入列表
            slaveSourceListForCorrelation.add(0,driverSourcePojo);
            List<SlaveSourcePojo> slaveSourceList = slaveSourcesObject.toJavaList(SlaveSourcePojo.class);
            BiRelTableEnum biRelTableEnum = customHelp.getBiRelTableEnum(hasSecondSlave, slaveSourceList, driverSourcePojo.getBusinessType(),driverSourcePojo.getSaasMark());
            for (SlaveSourcePojo slaveSourcePojo:slaveSourceList){
                BiDataCorrelationEntity biDataCorrelationEntity =biDataCorrelationModel.findSlaveLocation(chartEntity.getCorpid(),
                        jsonObject.getLong("appId"), slaveSourcePojo.getFormId(),
                        jsonObject.getInteger("saasMark"), jsonObject.getInteger("businessType"), biRelTableEnum.getCode(),slaveSourcePojo.getLinkAttr());
                if (biDataCorrelationEntity.getLocation()==2){
                    boolQueryBuilder.filter(termQuery("btformId", slaveSourcePojo.getFormId()));
                    slaveSourceListForCorrelation.add(1,slaveSourcePojo);
                }else if(biDataCorrelationEntity.getLocation()==3){
                    boolQueryBuilder.filter(termQuery("ctformId",slaveSourcePojo.getFormId()));
                    slaveSourceListForCorrelation.add(2,slaveSourcePojo);
                }

            }
        }
        List<ConditionsEntityExt> conditionsList = new ArrayList();
        JSONArray filterList = chartEntity.getFilter();
        if (CollectionsUtil.isNotEmpty(filterList)){
            for (int i = 0; i < filterList.size(); i++) {
                JSONObject jsonObject = filterList.getJSONObject(i);
                ConditionsEntityExt conditions = new ConditionsEntityExt();
                BeanUtil.copyProperties(conditions, jsonObject);
                conditionsList.add(conditions);
            }
        }
        EsUtil.parseCondition(boolQueryBuilder,conditionsList,null,null,null);
        JSONArray tableHead = new JSONArray();
        JSONObject result = new JSONObject();
        ResultTableVO resultTableVO = new ResultTableVO();
        //根据图表类型的不同渲染格式也不同
        switch (ChartTypeEnum.getByCode(chartEntity.getChartType())){
            case DATA_QUERY_TABLE:
                JSONArray displayAttrArray =  chartEntity.getDisplayAttr();
                //数据查询表先拼装展示数据
                displayAttrAssemble(displayAttrArray,nativeSearchQueryBuilder,slaveSourceListForCorrelation,chartEntity.getChartType(),tableHead);
//                List<StatisticPaasFormDataEsEntity> esEntities= elasticsearchTemplate.queryForList(searchQuery,StatisticPaasFormDataEsEntity.class);
                //encapsulateTableData(resultTableVO,tableHead,esEntities);
                List<ResultTableVO> resultTableVOList = new ArrayList<>();
                break;
            case DATA_STATISTICS_TABLE:
                JSONArray groupAttrArray = chartEntity.getGroupAttr();
                displayAttrAssemble(groupAttrArray,nativeSearchQueryBuilder,slaveSourceListForCorrelation,chartEntity.getChartType(),tableHead);
/*                List<StatisticPaasFormDataEsEntity> entities= elasticsearchTemplate.queryForList(searchQuery,StatisticPaasFormDataEsEntity.class);
                encqpsulateStatisticsTable(tableHead,entities);*/
                break;
            case BAR_CHART:
                break;
            case LINE_CHART:
                break;
            case AREA_CHART:
                break;
            case RADAR_CHART:
                break;
            case PIE_CHART:
                break;
            default:
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224015, StatisticsServicesErrorCodeEnum.API_ERROR_224015.getMsg());
        }

        return result;

}

    /**
     * 渲染统计表
     * @param tableHead 表头信息
     * @param esEntities ES查询出来的信息
     * @return
     */
    private JSONObject encqpsulateStatisticsTable(JSONArray tableHead,List<StatisticPaasFormDataEsEntity> esEntities){
         JSONObject table = new JSONObject();
        JSONArray row = new JSONArray();
        table.put("tableHead",tableHead);
        for (StatisticPaasFormDataEsEntity statisticPaasFormDataEsEntity:esEntities){
            JSONObject tableData = new JSONObject();
            for(int i=0;i<tableHead.size();i++){
                JSONArray subArray = null;
                if(tableData.containsKey("sub")){
                    subArray = tableData.getJSONArray("sub");
                }
                JSONObject subObject = new JSONObject();
                JSONObject dataObject = tableHead.getJSONObject(i);
                String  key= dataObject.getString("key");
                String[] keySplit = key.split("&");
                JSONObject data =  (JSONObject) ReflectHelper.valueGet(statisticPaasFormDataEsEntity,keySplit[1]);
                if (subArray!=null){
                    subObject.put("key",key);
                    subObject.put("value",data.getString(keySplit[2]));
                    subObject.put("sub",new JSONArray());
                }else{
                    //拼接数据的行
                    tableData.put("key",key);
                    tableData.put("value",data.getString(keySplit[2]));
                    tableData.put("sub",new JSONArray());
                }

            }
            row.add(tableData);
        }
        table.put("tableData",row);
        return table;
    }

  /*
    private void encapsulateTableData(ResultTableVO resultTableVO,JSONArray tableHead,List<StatisticPaasFormDataEsEntity> esEntities){
        JSONObject table = new JSONObject();
        JSONArray row = new JSONArray();
        List<JSONObject> headList = JSONObject.parseArray(tableHead.toJSONString(),JSONObject.class);
        resultTableVO.setCustomTitle(headList);
        //table.put("tableHead",tableHead);
        for (StatisticPaasFormDataEsEntity statisticPaasFormDataEsEntity:esEntities){
            JSONObject tableData = new JSONObject();
            for(int i=0;i<tableHead.size();i++){
                JSONObject dataObject = tableHead.getJSONObject(i);
                String  key= dataObject.getString("key");
                String[] keySplit = key.split("&");
                JSONObject data =  (JSONObject) ReflectHelper.valueGet(statisticPaasFormDataEsEntity,keySplit[1]);
                //拼接数据的行
                tableData.put(key,data.getString(keySplit[2]));
            }
            row.add(tableData);
        }
        List<JSONObject> dataList = JSONObject.parseArray(row.toJSONString(),JSONObject.class);
        resultTableVO.setCustomData(dataList);
        //table.put("tableData",row);
    }*/

    /**
     * 查询表的自定义展现数据
     * @param attrArray
     * @param nativeSearchQueryBuilder
     * @param slaveSourceListForCorrelation
     * @param chartType
     * @param tableHead
     */
    private void displayAttrAssemble(JSONArray attrArray,NativeSearchQueryBuilder nativeSearchQueryBuilder
            ,List<SlaveSourcePojo> slaveSourceListForCorrelation,Integer chartType,JSONArray tableHead){
        if (!attrArray.isEmpty()){
            String[] fields = new String[attrArray.size()];
            for (int i=0;i<attrArray.size();i++){
                JSONObject jsonObject = attrArray.getJSONObject(i);
                String formId = jsonObject.getString("formId");
                String attr = jsonObject.getString("attr");
                for(int j=0;j<slaveSourceListForCorrelation.size();j++){
                    if(formId.equals(String.valueOf(slaveSourceListForCorrelation.get(j).getFormId()))){
                        String dataName = null;
                        switch (j) {
                            case 0:
                                dataName = "atdata";
                                break;
                            case 1:
                                dataName = "btdata";
                                break;
                            case 2:
                                dataName = "ctdata";
                                break;
                            default:
                                break;
                        }
                        if (ChartTypeEnum.getByCode(chartType).equals(ChartTypeEnum.DATA_QUERY_TABLE)){
                            String attrName = jsonObject.getString("name");
                            JSONObject headName = new JSONObject();
                            headName.put("name",attrName);
                            headName.put("key",formId+"&"+dataName+"&"+attr);
                            tableHead.add(headName);
                        }
                        fields[i] = dataName+"."+attr;
                        break;
                    }
                }
            }
            nativeSearchQueryBuilder.withFields(fields);
        }
    }


    @RequestMapping(value = "/aggTwoTable", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String aggTwoTable(@RequestBody @Valid DepartmentListDTO departmentListDTO, BindingResult br) throws Exception {
        XbbResponse response;

        FormDataListDTO formDataListDTO = new FormDataListDTO() ;
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        //解析查询条件
        EsUtil.parseCondition(boolQueryBuilder,formDataListDTO.getConditions(),formDataListDTO.getRel(),null,null);
        // 拼接appId，菜单id等数据
        EsUtil.getTermQuery(boolQueryBuilder, formDataListDTO, true);
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        //排序
        SortOrder order = SortOrder.DESC;
        String sortField = "updateTime";
        Map<String, String> sortMap = formDataListDTO.getSortMap();
        if(sortMap != null && !sortMap.isEmpty()){
            sortField = (StringUtil.isEmpty(sortMap.get("field")) ? sortField : sortMap.get("field"));
            Map<String, FieldAttrEntity> explainMap = formDataListDTO.getExplainMap();
            if(explainMap.containsKey(sortField)){
                String raw = ".raw";
                String split = "_";
                if(sortField.split(split)[0].equals(FieldTypeEnum.TEXT.getEsalias())){
                    sortField = sortField + raw;
                }
                sortField = "data."+sortField;
            }
            String sort = "sort";
            if(SortOrder.ASC.toString().equals(sortMap.get(sort))){
                order = SortOrder.ASC;
            }
        }
        nativeSearchQueryBuilder.withSort(new FieldSortBuilder(sortField).order(order));
        //限定返回值
        List<String> fieldList = formDataListDTO.getFieldList();
        EsUtil.setFieldList(nativeSearchQueryBuilder, fieldList);
        //分页
        Integer page = formDataListDTO.getPage();
        Integer pageSize = formDataListDTO.getPageSize();
        EsUtil.setPage(nativeSearchQueryBuilder, page, pageSize);
/*        nativeSearchQueryBuilder.withIndices(statisticIndexName).withTypes(statisticType);
        SearchQuery searchQuery = nativeSearchQueryBuilder.build();*/
//        AggregatedPage<StatisticPaasFormDataEsEntity> esEntities = elasticsearchTemplate.queryForPage(searchQuery, StatisticPaasFormDataEsEntity.class);
        response = new XbbResponse<>();
        return JSON.toJSONString(response);
    }
    @RequestMapping(value = "/createIndexTest", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String createIndexTest(@RequestBody @Valid DepartmentListDTO departmentListDTO, BindingResult br) throws Exception {
        XbbResponse<PaasFormDataEsInitVO> response;
        PaasFormDataEsInitVO paasFormDataEsInitVO = new PaasFormDataEsInitVO();
        BiRelTableEnum biRelTableEnum = BiRelTableEnum .IDX_STATISTIC_PASS_DATA;

/*
        elasticsearchTemplate.deleteIndex(biRelTableEnum.getIndex());
        elasticsearchTemplate.createIndex(biRelTableEnum.getIndex(), "{\"index\":{\"mapping\":{\"total_fields\":{\"limit\":\"3000\"}},\"analysis\":{\"analyzer\":{\"chinese_text\":{\"filter\":[\"chinese_text\"],\"tokenizer\":\"keyword\"},\"email_url_analyzer\":{\"filter\":[\"trim\"],\"tokenizer\":\"uax_url_email\",\"type\":\"custom\"},\"index_email_analyzer\":{\"filter\":[\"lowercase\",\"name_ngram_filter\",\"trim\"],\"tokenizer\":\"standard\",\"type\":\"custom\"},\"index_phone_analyzer\":{\"char_filter\":[\"digit_only\"],\"filter\":[\"trim\"],\"tokenizer\":\"digit_edge_ngram_tokenizer\",\"type\":\"custom\"},\"search_email_analyzer\":{\"filter\":[\"lowercase\",\"trim\"],\"tokenizer\":\"standard\",\"type\":\"custom\"},\"search_phone_analyzer\":{\"char_filter\":[\"digit_only\"],\"filter\":[\"trim\"],\"tokenizer\":\"keyword\",\"type\":\"custom\"}},\"char_filter\":{\"digit_only\":{\"pattern\":\"\\\\D+\",\"replacement\":\"\",\"type\":\"pattern_replace\"}},\"filter\":{\"chinese_text\":{\"country\":\"CN\",\"language\":\"cn\",\"type\":\"icu_collation\"},\"name_ngram_filter\":{\"max_gram\":\"20\",\"min_gram\":\"1\",\"type\":\"ngram\"}},\"tokenizer\":{\"digit_edge_ngram_tokenizer\":{\"max_gram\":\"15\",\"min_gram\":\"1\",\"token_chars\":[\"digit\"],\"type\":\"edgeNGram\"}}}}}");
*/

        JSONObject mappingJson = (JSONObject) JSONObject.parse(EsMappingConstant.ELASTIC_MAPPING_ROOT);
        JSONObject properties = mappingJson.getJSONObject("properties");
        JSONObject crossJson = getJsonObject("at");
        properties.putAll(crossJson);
        JSONObject crossJson1 = getJsonObject("bt");
        properties.putAll(crossJson1);
        JSONObject crossJson2 = getJsonObject("ct");
        properties.putAll(crossJson2);
//        elasticsearchTemplate.putMapping(biRelTableEnum.getIndex(), biRelTableEnum.getType(), JSON.toJSONString(mappingJson, SerializerFeature.DisableCircularReferenceDetect));

        response = new XbbResponse<>(paasFormDataEsInitVO);
        return JSON.toJSONString(response);
    }

    private JSONObject getJsonObject(String pre) {
        //外层
        JSONObject outJsonObject = new JSONObject();
        //内层
        JSONObject subFormJson = new JSONObject();
        //公有部分
        JSONObject newJsonObject = new JSONObject();
        //内层数量减半
        JSONObject inJsonObject = new JSONObject();

        for (int i = 1; i <= FieldTypeEnum.TEXT.getMax(); i++) {
            newJsonObject.put(pre+"data.text_"+i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_STRING_SORT));
        }
        for (int i = 1; i <= FieldTypeEnum.NUM.getMax(); i++) {
            newJsonObject.put(pre+"data.num_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_DOUBLE));
        }
        for (int i = 1; i <= FieldTypeEnum.DATETIME.getMax(); i++) {
            newJsonObject.put(pre+"data.date_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_DATE_SECOND));
        }
        for (int i = 1; i <= FieldTypeEnum.LOCATION.getMax(); i++) {
            newJsonObject.put(pre+"data.geo_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_LOCATION));
        }
        for (int i = 1; i <= FieldTypeEnum.ADDRESS.getMax(); i++) {
            newJsonObject.put(pre+"data.address_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_ADDRESS));
        }
        for (int i = 1; i <= FieldTypeEnum.UPLOAD.getMax(); i++) {
            newJsonObject.put(pre+"data.file_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_TEXT));
        }
        //数组类型 内部定义为
        for (int i = 1; i <= FieldTypeEnum.USER_GROUP.getMax(); i++) {
            newJsonObject.put(pre+"data.array_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_TEXT));
        }
        //子表单
        for (int i = 1; i <= SubFieldTypeEnum.TEXT.getMax(); i++) {
            inJsonObject.put("text_"+i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_STRING_SORT));
        }
        for (int i = 1; i <= SubFieldTypeEnum.NUM.getMax(); i++) {
            inJsonObject.put("num_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_DOUBLE));
        }
        for (int i = 1; i <= SubFieldTypeEnum.DATETIME.getMax(); i++) {
            inJsonObject.put("date_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_DATE_SECOND));
        }
        for (int i = 1; i <= SubFieldTypeEnum.LOCATION.getMax(); i++) {
            inJsonObject.put("geo_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_LOCATION));
        }
        for (int i = 1; i <= SubFieldTypeEnum.ADDRESS.getMax(); i++) {
            inJsonObject.put("address_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_ADDRESS));
        }
        for (int i = 1; i <= SubFieldTypeEnum.UPLOAD.getMax(); i++) {
            inJsonObject.put("file_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_TEXT));
        }
        //数组类型
        for (int i = 1; i <= SubFieldTypeEnum.USERGROUP.getMax(); i++) {
            inJsonObject.put("array_" + i, (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_TEXT));
        }
        subFormJson.put("properties",inJsonObject);
        //子表单数量限制3个
        for (int i = 1; i <= FieldTypeEnum.SUB_FORM.getMax(); i++) {
            outJsonObject.put(pre+"data.subForm_" + i, subFormJson);
        }
        //addTime
        outJsonObject.put(pre+"addTime", (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_DATE_SECOND));
        //lastConnectTime
        outJsonObject.put(pre+"updateTime", (JSONObject) JSONObject.parse(EsMappingConstant.MAPPING_FOR_DATE_SECOND));

        outJsonObject.putAll(newJsonObject);
        return outJsonObject;
    }

    @RequestMapping(value = "/initDataTest", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String initDataTest(@RequestBody @Valid DepartmentListDTO departmentListDTO, BindingResult br) throws Exception {
        XbbResponse<PaasFormDataEsInitVO> response;
        PaasFormDataEsInitVO paasFormDataEsInitVO = new PaasFormDataEsInitVO();
        boolean flag = true;
        //TODO  首先理清关联关系
        //首先要判断关联字段是系统字段还是自定义字段（是否在data内）
        String condition = "";
        List<CorrelationEntity> correlationList = JSONObject.parseArray(condition, CorrelationEntity.class);
        CorrelationEntity correlationEntity = correlationList.get(0);
        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        params.put("orderByStr", "id");
        params.put("appId", correlationEntity.getAtAppId());
        params.put("menuId", correlationEntity.getAtMenuId());
        while (flag){
            List<PaasFormDataEntityExt> alist = paasFormDataModel.findEntityOriginal(params);
            if(alist == null || alist.isEmpty()){
                flag = false;
            }else {
                //大于上次最大的id
                params.put("idGte", alist.get(alist.size()-1).getId());
                List<Object> crossList = new ArrayList<>();
                Map<String,PaasFormDataEntity> btMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (PaasFormDataEntity aentity : alist) {
                    crossList.add(valueGet(aentity,correlationEntity.getAtKey()));
                }


                StatisticPaasFormDataEsEntity statisticPaasFormDataEsEntity = new StatisticPaasFormDataEsEntity();
            }
        }
        response = new XbbResponse<>(paasFormDataEsInitVO);
        return JSON.toJSONString(response);
    }
    public static Object valueGet(Object obj, String key){
        if (obj == null) {
            return null;
        }

        try {
            Field[] fields = obj.getClass().getDeclaredFields();
            Field field;
            for (int i = 0; i < fields.length; i++) {
                field = fields[i];
                // 修改访问权限
                field.setAccessible(true);
                if (key.equals(field.getName())) {
                    return field.get(obj);
                }
            }

        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * TODO 要判断是单表还是多表（2表或3表）
     * TODO  1对多的以驱动表为主
     * @param departmentListDTO
     * @param br
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/scroll", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String scroll(@RequestBody @Valid DepartmentListDTO departmentListDTO, BindingResult br) throws Exception {
        XbbResponse<PaasFormDataEsListVO> response;

        //首先要判断关联字段是系统字段还是自定义字段（是否在data内）
//        String condition = "[{\"atAppId\":142,\"atKey\":\"data.num_1\",\"atMenuId\":4096,\"atName\":\"客户电话\",\"attrType\":\"num\",\"btAppId\":142,\"btKey\":\"data.num_1\",\"btMenuId\":4120,\"btName\":\"客户电话\",\"ctAppId\":142,\"ctKey\":\"data.num_2\",\"ctMenuId\":4230,\"ctName\":\"客户电话\"}]";
        String condition = "{\"atAppId\":142,\"atIsData\":1,\"atKey\":\"num_1\",\"atMenuId\":4096,\"atName\":\"客户电话\",\"attrType\":\"num\",\"btAppId\":142,\"btIsData\":1,\"btKey\":\"num_1\",\"btMenuId\":4120,\"btName\":\"客户电话\",\"ctAppId\":142,\"ctIsData\":1,\"ctKey\":\"num_2\",\"ctMenuId\":4230,\"ctName\":\"客户电话\"}";
//        String condition = "[{\"atAppId\":142,\"atIsData\":1,\"atKey\":\"text_1\",\"atMenuId\":4096,\"atName\":\"客户电话\",\"attrType\":\"num\",\"btAppId\":142,\"btIsData\":1,\"btKey\":\"text_3\",\"btMenuId\":4120,\"btName\":\"客户电话\",\"ctAppId\":142,\"ctIsData\":1,\"ctKey\":\"text_2\",\"ctMenuId\":4230,\"ctName\":\"客户电话\"}]";
        CorrelationEntity correlationEntity  = JSONObject.parseObject(condition, CorrelationEntity.class);
        String corpid = "1";
        PaasFormDataEsListVO listVO = new PaasFormDataEsListVO();
        PageRequest pageRequest = PageRequest.of(0, 10000);
        BoolQueryBuilder boolQueryBuilder = boolQuery()
                .filter(termQuery("corpid.keyword", corpid))
                .filter(termQuery("appId",correlationEntity.getAtAppId()))
                .filter(termQuery("menuId",correlationEntity.getAtMenuId()));
/*        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withIndices("idx_form_data").withTypes("form_data")
                .withQuery(boolQueryBuilder)
                .withPageable(pageRequest)
                .build();*/

        //1m=1分钟
        int scrollTimeInMillis = 60000;
//        ScrolledPage<PaasFormDataEntityExt> scroll = (ScrolledPage<PaasFormDataEntityExt>) elasticsearchTemplate.startScroll(scrollTimeInMillis, searchQuery, PaasFormDataEntityExt.class);
        List<PaasFormDataEntityExt> atList = new ArrayList<>();
        //判断是自定义字段，还是其他
        int atIsData = correlationEntity.getAtIsData();
        int btIsData = correlationEntity.getBtIsData();
        int ctIsData = correlationEntity.getCtIsData();
        String atKey = correlationEntity.getAtKey();
        String btKey = correlationEntity.getBtKey();
        String ctKey = correlationEntity.getCtKey();
        //TODO  移除 ElasticsearchTemplate改为了true
        while (true) {
            List<PaasFormDataEntityExt> firstList = new ArrayList<>();
            atList.addAll(firstList);
            Set<Object> aFilterSet = new HashSet<>();
            for (PaasFormDataEntityExt paasFormDataEsEntity : firstList) {
                Object key ;
                if(atIsData == 1){
                    key = paasFormDataEsEntity.getData().get(atKey);
                }else{
                    key = ReflectHelper.valueGet(paasFormDataEsEntity,atKey);
                }
                if(key == null){
                    continue;
                }
                aFilterSet.add(key);
            }
            //TODO aFilterlist不为空再往下进行
            Map<Object,PaasFormDataEntityExt> bMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Object,PaasFormDataEntityExt> cMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if(aFilterSet != null  &&  !aFilterSet.isEmpty()){
                //
                SlaveListDTO slaveListDTO = new SlaveListDTO();
                slaveListDTO.setCorpid(corpid);
                slaveListDTO.setSlaveSet(aFilterSet);
                slaveListDTO.setSlaveMap(bMap);
                slaveListDTO.setInData(btIsData);
                slaveListDTO.setAppId(correlationEntity.getBtAppId());
//                slaveListDTO.setMenuId(correlationEntity.getBtMenuId());
                slaveListDTO.setLinkAttr(btKey);
                slaveList(slaveListDTO);
                //存在第三张表
                if(!StringUtil.isEmpty(ctKey)){
                    slaveListDTO = new SlaveListDTO();
                    slaveListDTO.setCorpid(corpid);
                    slaveListDTO.setSlaveSet(aFilterSet);
                    slaveListDTO.setSlaveMap(cMap);
                    slaveListDTO.setInData(ctIsData);
                    slaveListDTO.setAppId(correlationEntity.getCtAppId());
//                    slaveListDTO.setMenuId(correlationEntity.getCtMenuId());
                    slaveListDTO.setLinkAttr(ctKey);
                    slaveList(slaveListDTO);
                }
            }

            BulkRequest bulkRequest = new BulkRequest();
            for (PaasFormDataEntityExt firstEntity : firstList) {
                Object key ;
                if(atIsData == 1){
                    key = firstEntity.getData().get(atKey);
                }else {
                    key = ReflectHelper.valueGet(firstEntity,atKey);
                }
                if(key == null){
                    continue;
                }
                StatisticPaasFormDataEsEntity  statisticPaasFormDataEsEntity = new StatisticPaasFormDataEsEntity();
//                statisticPaasFormDataEsEntity.putAtEntity(firstEntity);
                //
                PaasFormDataEntityExt secondEntity = bMap.get(key);
                if (secondEntity != null) {
//                    statisticPaasFormDataEsEntity.putBtEntity(secondEntity);
                }
                //
                PaasFormDataEntityExt thirdEntity = cMap.get(key);
                if(thirdEntity != null){
                    statisticPaasFormDataEsEntity.putCtEntity(thirdEntity);
                }

                IndexRequest indexRequest = new IndexRequest();
                indexRequest
                        .index(statisticIndexName)
                        .type(statisticType)
//                        .setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL)
                        .source(BeanUtil.convertBean2Map(statisticPaasFormDataEsEntity,false,true))
                        //设置id，使用UUID,  导致不可全覆盖，只能更新
                        .id(UUID.randomUUID().toString())
                ;
                bulkRequest.add(indexRequest);
            }
          /*  Client client = elasticsearchTemplate.getClient();
            client.bulk(bulkRequest).get();*/

            //TODO  下次循环时间过长会不会断掉(如果会断掉，1：调小步长，2不用scroll(效率可能会比较低) 3.先取出，内存是否会爆)
//            scroll = (ScrolledPage<PaasFormDataEntityExt>) elasticsearchTemplate.continueScroll(scroll.getScrollId() , scrollTimeInMillis, PaasFormDataEntityExt.class);
        }
//        elasticsearchTemplate.clearScroll(scroll.getScrollId());
/*        response = new XbbResponse<>(listVO);
        return JSON.toJSONString(response);*/
    }


    @RequestMapping(value = "/updateDataWarehouse", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String updateDataWarehouse(@RequestBody @Valid DepartmentListDTO departmentListDTO, BindingResult br) throws Exception {
        XbbResponse<PaasFormDataEsListVO> response;
        PaasFormDataEsListVO listVO = new PaasFormDataEsListVO();
        String condition = "{\"atAppId\":142,\"atIsData\":1,\"atKey\":\"num_1\",\"atMenuId\":4096,\"atName\":\"客户电话\",\"attrType\":\"num\",\"btAppId\":142,\"btIsData\":1,\"btKey\":\"num_1\",\"btMenuId\":4120,\"btName\":\"客户电话\",\"ctAppId\":142,\"ctIsData\":1,\"ctKey\":\"num_2\",\"ctMenuId\":4230,\"ctName\":\"客户电话\"}";
//        String condition = "[{\"atAppId\":142,\"atIsData\":1,\"atKey\":\"text_1\",\"atMenuId\":4096,\"atName\":\"客户电话\",\"attrType\":\"num\",\"btAppId\":142,\"btIsData\":1,\"btKey\":\"text_3\",\"btMenuId\":4120,\"btName\":\"客户电话\",\"ctAppId\":142,\"ctIsData\":1,\"ctKey\":\"text_2\",\"ctMenuId\":4230,\"ctName\":\"客户电话\"}]";
        CorrelationEntity  correlationEntity = JSONObject.parseObject(condition, CorrelationEntity.class);
        System.out.println(correlationEntity);

        response = new XbbResponse<>(listVO);
        return JSON.toJSONString(response);
    }

    @RequestMapping(value = "/combinations", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String combinations(@RequestBody @Valid DepartmentListDTO departmentListDTO, BindingResult br) throws Exception {
        XbbResponse<PaasFormDataEsListVO> response;
        PaasFormDataEsListVO listVO = new PaasFormDataEsListVO();
        String str = "客户,销售机会,跟进记录,合同订单,应收款,发票,工单,产品,采购合同,采购退货,供应商,库存,入库单,出库单,生产单";
        String[] strArray = str.split(",");
        System.out.println("===============================kaishi");
//        combinationSelect(strArray,3);
        System.out.println("===============================结束");
        arrangementSelect(strArray,3);
        System.out.println("===============================end");
        Map<String, Object> map = new HashMap<>();
        map.put("id",100555);
        Integer aa = 0;
        aa = customerModel.getEntitysCount(map);
        response = new XbbResponse<>(listVO);
        return JSON.toJSONString(response);
    }



    private static long factorial(int n) {
        long sum = 1;
        while( n > 0 ) {
            sum = sum * n--;
        }
        return sum;
    }

    public static long arrangement(int m, int n) {
        return m <= n ? factorial(n) / factorial(n - m) : 0;
    }

    public static void arrangementSelect(String[] dataList, int n) {
        System.out.println(String.format("A(%d, %d) = %d", dataList.length, n,
                arrangement(n, dataList.length)));
        arrangementSelect(dataList, new String[n], 0);
    }
    private static void arrangementSelect(String[] dataList, String[] resultList, int resultIndex) {
        int resultLen = resultList.length;
        // 全部选择完时，输出排列结果
        if (resultIndex >= resultLen) {
            System.out.println(Arrays.asList(resultList));
            return;
        }

        // 递归选择下一个
        for (int i = 0; i < dataList.length; i++) {
            // 判断待选项是否存在于排列结果中
            boolean exists = false;
            for (int j = 0; j < resultIndex; j++) {
                if (dataList[i].equals(resultList[j])) {
                    exists = true;
                    break;
                }
            }
            // 排列结果不存在该项，才可选择
            if (!exists) {
                resultList[resultIndex] = dataList[i];
                arrangementSelect(dataList, resultList, resultIndex + 1);
            }
        }
    }

    /**
     * 组合选择（从列表中选择n个组合）
     * @param dataList 待选列表
     * @param n 选择个数
     */
    public static void combinationSelect(String[] dataList, int n) {
        System.out.println(String.format("C(%d, %d) = %d",
                dataList.length, n, combination(dataList.length, n)));
        combinationSelect(dataList, 0, new String[n], 0);
    }
    public static long combination(int m, int n) {
        return m <= n ? factorial(n) / (factorial(m) * factorial((n - m))) : 0;
    }
    /**
     * 组合选择
     * @param dataList 待选列表
     * @param dataIndex 待选开始索引
     * @param resultList 前面（resultIndex-1）个的组合结果
     * @param resultIndex 选择索引，从0开始
     */


    private static void combinationSelect(String[] dataList, int dataIndex, String[] resultList, int resultIndex) {
        int resultLen = resultList.length;
        int resultCount = resultIndex + 1;
        // 全部选择完时，输出组合结果
        if (resultCount > resultLen) {
            List<String> list = Arrays.asList(resultList);
            System.out.println(list);
            return;
        }

        // 递归选择下一个
        for (int i = dataIndex; i < dataList.length + resultCount - resultLen; i++) {
            resultList[resultIndex] = dataList[i];
            combinationSelect(dataList, i + 1, resultList, resultIndex + 1);
        }
    }



    public static void main(String[] args) {
        String digitUpperMoney = "";
        digitUpperMoney = digitUpperMoney.replaceAll("元", "美元");
        System.out.println(digitUpperMoney);
    }
    /**
     * 返回拼装好的k-v和k
     * @param slaveListDTO
     * @return
     */
    public Set<Object> slaveList(SlaveListDTO slaveListDTO) {
        BoolQueryBuilder  boolQueryBuilder = boolQuery();
        Set<Object> slaveSet = new HashSet<>();
        String slaveKey = slaveListDTO.getLinkAttr();
        int inData = slaveListDTO.getInData();
        //TODO  这里要判断字段类型，如果是String，可能要加.keyword
        String filterKey = slaveKey;
        if (inData == 1) {
            filterKey = "data." + slaveKey;
        }
        boolQueryBuilder
                .filter(termQuery("corpid.keyword", slaveListDTO.getCorpid()))
                .filter(termQuery("appId", slaveListDTO.getAppId()))
//                .filter(termQuery("menuId", slaveListDTO.getMenuId()))
                .filter(termsQuery(filterKey, slaveListDTO.getSlaveSet()));
/*        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withIndices("idx_form_data").withTypes("form_data")
                .withQuery(boolQueryBuilder)
                .build();*/
//        AggregatedPage<PaasFormDataEntityExt> secondList = elasticsearchTemplate.queryForPage(searchQuery, PaasFormDataEntityExt.class);
        Map<Object, PaasFormDataEntityExt> slaveMap = slaveListDTO.getSlaveMap();
     /*   for (PaasFormDataEntityExt paasFormDataEsEntity : secondList) {
            Object key;
            if (inData == 1) {
                key = paasFormDataEsEntity.getData().get(slaveKey);
            } else {
                key = ReflectHelper.valueGet(paasFormDataEsEntity, slaveKey);
            }
            slaveMap.put(key, paasFormDataEsEntity);
            slaveSet.add(key);
        }*/
        slaveListDTO.setSlaveMap(slaveMap);
        return slaveSet;
    }
}
